DOM diff
无 key
1 | <html> |
从触发 setState 进入到 WorkLoop 后进入 beginWork 开始,这里生成新的 Fiber 树
1 | function beginWork(current$$1, workInProgress, renderExpirationTime) { |
小结-无 key 的时候
setState 会更新某个 FiberNode 的 updateQueue,之后可以得到被更新的数据。
FiberNode 新的与旧的之间比较,是遍历新生成 newChildren 数组(只有 2 项)
刚进来的时候,声明了几个变量
oldFiber (是旧的 FiberNode,它是第一项,它有两个兄弟 FiberNode)
newIdx = 0
nextOldFiber = null;
lastPlacedIndex = 0;
更新过程中复用了 oldFiber
首先 nextOldFiber 变为了 oldFiber.sibling,之后更新 oldFiber 为 newFiber,更新过程:先拿到 oldFiber 的 key,不存在就是 null。如果 newFiber 的 key 与 oldFIber 的 key 相等,就把 oldFiber 复用,克隆成一个新的 FiberNode,并且合并进去了新的数据,让它成为 newFiber。
第二次循环与第一次类似。
- 第三次进入 deleteRemainingChildren 方法,移除了最后一个节点,就是将倒数第二个的 sibling 指向 null
之后更新 Fiber 树,再进入 commit 阶段
先将列表最后一项从 dom 中移除,之后再逐个更新列表其他元素。需要注意的就是需要更新的节点会是一个链表,比如这边的 firstEffect.nextEffct.nextEffct,是在 renderRoot 阶段里的 workLoop 里生成的
看下具体生成的步骤
这里的 firstEffect 是在 reconcileChildrenArray 里生成的(就是更新 Fiber树的时候),在第三个 FiberNode 删除的时候添加到 returnFiber 上
在 completeUnitOfWork 方法做的链接(也就是生成 stateNode 与做链接关系是一件事)
有 key
1 | <html> |
主要区别应该是在 reconcileChildrenArray 方法,更新 Fiber 树的地方
在进入到 updateSlot
1 | function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { |
用 map 通过 key 把对应的 FiberNode 存起来
1 | function mapRemainingChildren(returnFiber, currentFirstChild) { |
之后还是遍历 newChildren 数组,取出对应的 FiberNode 做更新,还剩下的 existingChildren 里的被删除
1 | for (; newIdx < newChildren.length; newIdx++) { |